package io.wongxd.demo

import android.text.format.Formatter
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraintsScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.wongxd.solution.compose.core.modifier.throttleClick
import io.wongxd.solution.util.device.getRomType
import io.wongxd.solution.util.network.NetworkBandwidth
import io.wongxd.solution.util.network.NetworkBandwidthSampler
import io.wongxd.solution.util.network.NetworkConnectivity
import io.wongxd.solution.util.network.NetworkState
import io.wongxd.solution.util.network.NetworkStreamTotal
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.text.NumberFormat

@Composable
fun BoxWithConstraintsScope.DebugInfo() {
    var expend by remember {
        mutableStateOf(false)
    }

    val size = 48.dp
    val edgeProtection = 30.dp
    val defaultRightMargin = with(LocalDensity.current) {
        30.dp.toPx()
    }
    val defaultBottomMargin = with(LocalDensity.current) {
        140.dp.toPx()
    }
    var offsetX by remember { mutableStateOf(-defaultRightMargin) }
    var offsetY by remember { mutableStateOf(-defaultBottomMargin) }

    val offsetXDp = with(LocalDensity.current) {
        offsetX.toDp().coerceAtLeast(-maxWidth + size + edgeProtection).coerceAtMost(-edgeProtection)
    }

    val offsetYDp = with(LocalDensity.current) {
        offsetY.toDp().coerceAtLeast(-maxHeight + size + edgeProtection).coerceAtMost(-edgeProtection)
    }

    if (expend) {
        Column(
            modifier = Modifier
                .align(Alignment.BottomEnd)
                .offset(offsetXDp, offsetYDp)
                .shadow(12.dp, RoundedCornerShape(8.dp), true)
                .background(Color.White)
                .throttleClick {
                    expend = false
                }
                .padding(14.dp)
        ) {
            NetworkBaseInfo()
            NetworkStreamTotalInfo()
            NetworkBandwidthInfo()
            Text(text = getRomType().name)
        }
    } else {
        Box(
            modifier = Modifier
                .align(Alignment.BottomEnd)
                .offset(offsetXDp, offsetYDp)
                .size(48.dp)
                .shadow(12.dp, CircleShape, true)
                .background(Color.White)
                .pointerInput(Unit) {
                    coroutineScope {
                        launch {
                            detectDragGestures { change, dragAmount ->
                                change.consume()
                                offsetX += dragAmount.x
                                offsetY += dragAmount.y
                            }
                        }

                        launch {
                            detectTapGestures {
                                expend = true
                            }
                        }
                    }
                }
        ) {
            Text(
                text = "Monitor",
                fontSize = 9.sp,
                color = Color.Black,
                modifier = Modifier.align(Alignment.Center)
            )
        }
    }
}

@Composable
fun NetworkBaseInfo() {
    val context = LocalContext.current
    val state = remember {
        mutableStateOf<NetworkState?>(null)
    }

    LaunchedEffect(context) {
        NetworkConnectivity.of(context).stateFlow.collectLatest {
            state.value = it
        }
    }

    val value = state.value
    if (value != null) {
        Column {
            Text("network type = ${value.networkType}")
            Text("valid = ${value.isValid}")
        }
    }
}

@Composable
fun NetworkStreamTotalInfo() {
    val context = LocalContext.current
    val state = remember {
        mutableStateOf(NetworkStreamTotal.ZERO)
    }

    LaunchedEffect(context) {
        NetworkBandwidthSampler.of(context).streamTotalFlow.collectLatest {
            state.value = it
        }
    }

    val value = state.value
    if (value != NetworkStreamTotal.ZERO) {
        Column {
            Text("total.up = ${Formatter.formatShortFileSize(context, value.up)}")
            Text("total.down = ${Formatter.formatShortFileSize(context, value.down)}")
        }
    }
}

@Composable
fun NetworkBandwidthInfo() {
    val context = LocalContext.current
    val state = remember {
        mutableStateOf(NetworkBandwidth.UNDEFINED)
    }

    val formatter = remember {
        val format = NumberFormat.getNumberInstance()
        format.maximumFractionDigits = 2
        format
    }

    LaunchedEffect(context) {
        NetworkBandwidthSampler.of(context).bandwidthFlow.collectLatest {
            state.value = it
        }
    }

    val value = state.value
    if (value != NetworkBandwidth.UNDEFINED) {
        Column {
            Text("bandwidth.up = ${formatter.format(value.up)} kbps")
            Text("bandwidth.down = ${formatter.format(value.down)} kbps")
        }
    }
}